package com.samuel.learning.custom.springmvc.demo.spring.servlet;

import com.samuel.learning.custom.springmvc.demo.spring.action.DemoAction;
import com.samuel.learning.custom.springmvc.demo.spring.annotation.AutoWired;
import com.samuel.learning.custom.springmvc.demo.spring.annotation.Controller;
import com.samuel.learning.custom.springmvc.demo.spring.annotation.Service;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

public class DispatcherSelvert extends HttpServlet {


    private Properties properties = new Properties();
    private Map<String, Object> beanMaps = new ConcurrentHashMap<String, Object>();
    private List<String> beanNameList = new ArrayList<String>();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }

    @Override
    public void init(ServletConfig config) throws ServletException {

        //开始初始化进程

        //定位
        doLoadConfig(config.getInitParameter("contextConfigLocation"));

        //加载,入参：类所在的包的路径
        doScanner(properties.getProperty("scanPackage"));

        //注册
        doRegistry();

        // 自动依赖注入
        doAutowired();

        DemoAction demoAction = (DemoAction) beanMaps.get("demoAction");
        demoAction.query(null, null, "sam");

        //解析mapping 将@RequestMapping中配置的url和一个Method关联上
        //以便于从浏览器获得用户输入的url以后，能够找到具体执行的Method通过反射去调用
        initHandlerMapping();
    }

    private void doLoadConfig(String location) {
        InputStream is = this.getClass().getClassLoader().getResourceAsStream(location.replace("classpath:", ""));

        try {
            properties.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void doScanner(String packageURI) {
        // 报的路径
        URL url = this.getClass().getClassLoader().getResource(packageURI.replaceAll("\\.", "/"));
        // 扫描目录下的,每个类文件
        File classDir = new File(url.getFile());
        for (File file : classDir.listFiles()) {
            if (file.isDirectory()) {
                doScanner(packageURI + "." + file.getName());
            } else {
                beanNameList.add(packageURI + "." + file.getName().replace(".class", ""));
            }


        }
    }

    private void doRegistry() {
        if (beanNameList.isEmpty()) {
            return;
        }
        try {
            for (String beanName : beanNameList) {

                Class<?> clazz = Class.forName(beanName);
                if (clazz.isAnnotationPresent(Controller.class)) {
                    String name = lowerFirstCase(clazz.getSimpleName());
                    beanMaps.put(name, clazz.newInstance());
                } else if (clazz.isAnnotationPresent(Service.class)) {
                    Service service = clazz.getAnnotation(Service.class);
                    String name = service.value();
                    if ("".equals(name.trim())) {
                        name = lowerFirstCase(clazz.getSimpleName());
                    }
                    beanMaps.put(name, clazz.newInstance());
                    //获得这个对象所实现的接口
                    Class<?>[] interfaces = clazz.getInterfaces();

                    for (Class<?> i : interfaces) {
                        beanMaps.put(i.getName(), clazz.newInstance());
                    }

                } else {
                    continue;
                }

            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    private void doAutowired() {

        if (beanMaps.isEmpty()) {
            return;
        }

        for (Map.Entry<String, Object> entry : beanMaps.entrySet()) {
            Field[] fields = entry.getValue().getClass().getDeclaredFields();
            for (Field field : fields) {

                if (!field.isAnnotationPresent(AutoWired.class)) {
                    continue;
                }
                AutoWired autoWired = field.getAnnotation(AutoWired.class);
                String name = autoWired.value().trim();
                if ("".equals(name)) {
                    name = field.getType().getName();
                }
                field.setAccessible(true);

                try {
                    field.set(entry.getValue(), beanMaps.get(name));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }

        }

    }

    public void initHandlerMapping() {

    }


    private String lowerFirstCase(String str) {
        char[] chars = str.toCharArray();
        chars[0] += 32;
        return String.valueOf(chars);
    }

}
